unit FileLogger;

interface

uses
  Winapi.Windows, System.SysUtils, CriticalSectionEx, IException;

type

  TFileLogger = class
  protected
    m_sPath: String;
    m_sData: String;

    m_bInit: Boolean;
    m_bLog: Boolean;
    m_sFileName: String;
    m_FLogFile: TextFile;

    m_bErrorLog: Boolean;
    m_sErrorFileName: String;
    m_FLogErrorFile: TextFile;

    m_bBusinessLog: Boolean;
    m_sBusinessFileName: String;
    m_FLogBusinessFile: TextFile;

    m_FileLock: TCriticalSectionEx;
    m_bShowProcessId: Boolean;
    m_bShowThreadId: Boolean;
    m_bShowDateTime: Boolean;
  private
    procedure isNewCreateFile;
  published
    property FbInit: Boolean read m_bInit;
    property IsShowProcessId: Boolean read m_bShowProcessId write m_bShowProcessId;
    property IsShowThreadId: Boolean read m_bShowThreadId write m_bShowThreadId;
    property IsShowDateTime: Boolean read m_bShowDateTime write m_bShowDateTime;
  public
    procedure InitFileLog(sFileName: String = '');
    procedure WriteLogMsg(const sMsg: string; const Args: array of const);
    procedure WriteErrorLogMsg(const sMsgErr: string; const Args: array of const);
    procedure WriteBusinessMsg(const sMsgBus: string; const Args: array of const);
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TFileLogger.Create;
begin
  inherited Create;
  m_bInit := FALSE;
  m_bShowProcessId := TRUE;
  m_bShowThreadId := TRUE;
  m_bShowDateTime := TRUE;

  m_bShowProcessId := FALSE;
  m_bShowThreadId := FALSE;
  m_bShowDateTime := FALSE;

  m_bLog := FALSE;
  m_bErrorLog := FALSE;
  m_bBusinessLog := FALSE;

  m_FileLock := TCriticalSectionEx.Create;
end;

procedure TFileLogger.InitFileLog(sFileName: String = '');
begin
  if m_bInit then Exit;

  m_sData := FormatDateTime('yyyymmdd', Now());
  m_sPath := ExtractFilePath(ParamStr(0))+'Log';
  if not DirectoryExists(m_sPath) Then CreateDir(m_sPath);
  m_sFileName := ExtractFilePath(ParamStr(0))+'Log\'+sFileName+m_sData+'_Log.txt';
  m_sErrorFileName := ExtractFilePath(ParamStr(0))+'Log\'+sFileName+m_sData+'_Error.txt';
  m_sBusinessFileName := ExtractFilePath(ParamStr(0))+'Log\'+sFileName+m_sData+'_Business.txt';


  try
    AssignFile(m_FLogFile, m_sFileName);
    if(FileExists(m_sFileName)) then
      append(m_FLogFile)
    else
      rewrite(m_FLogFile);

    m_bLog := True;
  except
    m_bLog := False;
    raise TException.Create(GetLastError(), 'WriteLogMsg');
  end;

  try
    AssignFile(m_FLogErrorFile, m_sErrorFileName);
    if(FileExists(m_sErrorFileName)) then
      append(m_FLogErrorFile)
    else
      rewrite(m_FLogErrorFile);

    m_bErrorLog := True;
  except
    m_bErrorLog := False;
    raise TException.Create(GetLastError(), 'WriteLogErrorMsg');
  end;

  try
    AssignFile(m_FLogBusinessFile, m_sBusinessFileName);
    if(FileExists(m_sBusinessFileName)) then
      append(m_FLogBusinessFile)
    else
      rewrite(m_FLogBusinessFile);

    m_bBusinessLog := True;
  except
    m_bBusinessLog := False;
    raise TException.Create(GetLastError(), 'WriteLogBusinessMsg');
  end;
  m_bInit := TRUE;
end;

destructor TFileLogger.Destroy;
begin
  FreeAndNil(m_FileLock);

  if m_bLog then CloseFile(m_FLogFile);
  if m_bErrorLog then CloseFile(m_FLogErrorFile);
  if m_bBusinessLog then CloseFile(m_FLogBusinessFile);
  inherited Destroy;
end;

procedure TFileLogger.isNewCreateFile;
var
  m_sOldData: String;
begin
  m_sOldData := FormatDateTime('yyyymmdd', Now());
  if Trim(m_sOldData) <> Trim(m_sData) then begin
    if m_bLog then CloseFile(m_FLogFile);
    if m_bErrorLog then CloseFile(m_FLogErrorFile);
    if m_bBusinessLog then CloseFile(m_FLogBusinessFile);

    m_sData := m_sOldData;
    m_sPath := ExtractFilePath(ParamStr(0))+'Log';
    if not DirectoryExists(m_sPath) Then CreateDir(m_sPath);
    m_sFileName := ExtractFilePath(ParamStr(0))+'Log\'+m_sData+'_Log.txt';
    m_sErrorFileName := ExtractFilePath(ParamStr(0))+'Log\'+m_sData+'_Error.txt';
    m_sBusinessFileName := ExtractFilePath(ParamStr(0))+'Log\'+m_sData+'_Business.txt';

    try
      AssignFile(m_FLogFile, m_sFileName);
      if(FileExists(m_sFileName)) then
        append(m_FLogFile)
      else
        rewrite(m_FLogFile);

      m_bLog := True;
    except
      m_bLog := False;
      raise TException.Create(GetLastError(), 'WriteLogMsg');
    end;

    try
      AssignFile(m_FLogErrorFile, m_sErrorFileName);
      if(FileExists(m_sErrorFileName)) then
        append(m_FLogErrorFile)
      else
        rewrite(m_FLogErrorFile);

      m_bErrorLog := True;
    except
      m_bErrorLog := False;
      raise TException.Create(GetLastError(), 'WriteLogErrorMsg');
    end;

    try
      AssignFile(m_FLogBusinessFile, m_sBusinessFileName);
      if(FileExists(m_sBusinessFileName)) then
        append(m_FLogBusinessFile)
      else
        rewrite(m_FLogBusinessFile);

      m_bBusinessLog := True;
    except
      m_bBusinessLog := False;
      raise TException.Create(GetLastError(), 'WriteLogBusinessMsg');
    end;
  end;
end;

procedure TFileLogger.WriteLogMsg(const sMsg: string; const Args: array of const);
begin
  if m_bLog then begin
    m_FileLock.Lock;
    isNewCreateFile;
    Writeln(m_FLogFile, Format( '%s  ProcessID: %d  ThreadID: %d %s ',
                                [FormatDateTime('hh:nn:ss:zzz',Now),
                                 GetCurrentProcessID(),
                                 GetCurrentThreadID(),
                                 Format(sMsg, Args)]));
    flush(m_FLogFile);
    m_FileLock.UnLock;
  end;
end;

procedure TFileLogger.WriteErrorLogMsg(const sMsgErr: string; const Args: array of const);
begin
  if m_bErrorLog then begin
    m_FileLock.Lock;
    isNewCreateFile;
    Writeln(m_FLogErrorFile, Format( '%s  ProcessID: %d  ThreadID: %d %s ',
                                     [FormatDateTime('hh:nn:ss:zzz',Now),
                                      GetCurrentProcessID(),
                                      GetCurrentThreadID(),
                                      Format(sMsgErr, Args)]));
    flush(m_FLogErrorFile);
    m_FileLock.UnLock;
    end;
end;

procedure TFileLogger.WriteBusinessMsg(const sMsgBus: string; const Args: array of const);
begin
  if m_bBusinessLog then begin
    m_FileLock.Lock;
    isNewCreateFile;
    Writeln(m_FLogBusinessFile, Format( '%s  ProcessID: %d  ThreadID: %d %s ',
                                        [FormatDateTime('hh:nn:ss:zzz',Now),
                                          GetCurrentProcessID(),
                                          GetCurrentThreadID(),
                                          Format(sMsgBus, Args)]));
    flush(m_FLogBusinessFile);
    m_FileLock.UnLock;
  end;
end;

end.
